// ///////////////////////////// MIT License //////////////////////////////////// //
//                                                                                //
// Copyright (c) 2010 David Zsolt Manrique                                        //
//                    david.zsolt.manrique@gmail.com                              //
//                                                                                //
// Permission is hereby granted, free of charge, to any person obtaining a copy   //
// of this software and associated documentation files (the "Software"), to deal  //
// in the Software without restriction, including without limitation the rights   //
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell      //
// copies of the Software, and to permit persons to whom the Software is          //
// furnished to do so, subject to the following conditions:                       //
//                                                                                //
// The above copyright notice and this permission notice shall be included in     //
// all copies or substantial portions of the Software.                            //
//                                                                                //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR     //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,       //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE    //
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER         //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,  //
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN      //
// THE SOFTWARE.                                                                  //
//                                                                                //
// ////////////////////////////////////////////////////////////////////////////// //

#ifndef POTENTIAL_H
#define POTENTIAL_H

//#include "potential_base.h"
#include "structure.h"
#include "inout.h"
#include "function.h"

struct internal_potential : potential_base
{
};

namespace background
{
	struct constant : internal_potential
	{
		param_type p_u0; //! k/2(d_ij-r0)^2
		constant(param_type p_u0);
		bool equivalent(const potential_base & r) const;
		static bool read(const std::string & input,const group_t & group,const topology_t& topology,potential_list_t & potential_list);
		std::string record_atom_index() const;
		std::string record_key() const;
		std::string record_params() const;
		void eval(real_type & u,vector_array_type & f,const vector_array_type & r) const;
	};

	struct constant_fit : constant
	{
		vector_index_type i_u0;
		constant_fit(param_type p_u0,  vector_index_type i_u0);
		static bool read(const std::string & input,const group_t & group,const topology_t& topology,potential_fit_list_t & potential_list);
		void peval(real_type & u,vectorx_type & dp,const vectorx_type & p,const vector_array_type & r);
		void pdiff(real_type & u,vectorx_type & dp,const vectorx_type & p,const vector_array_type & r);
	};

}

namespace bond
{
	struct potential : internal_potential
	{	
		array_index_type i,j; //! atom indecies
		potential(array_index_type i_,array_index_type j_);
		bool equivalent(const potential_base & r) const;
		std::string record_atom_index() const;
	};
	//!
	struct harm : potential
	{
		param_type p_k,p_r0; //! k/2(d_ij-r0)^2
		harm(param_type p_k,param_type p_r0, array_index_type i,array_index_type j);
		static bool read(const std::string & input,const group_t & group,const topology_t& topology,potential_list_t & potential_list);
		std::string record_key() const;
		std::string record_params() const;
		void eval(real_type & u,vector_array_type & f,const vector_array_type & r) const;
	};
	struct harm_fit : harm, fit_base
	{
		vector_index_type i_k,i_r0;
		harm_fit(param_type p_k,  vector_index_type i_k, 
			param_type p_r0, vector_index_type i_r0,  
			array_index_type i,array_index_type j);
		static bool read(const std::string & input,const group_t & group,const topology_t& topology,potential_fit_list_t & potential_list);
		void peval(real_type & u,vectorx_type & dp,const vectorx_type & p,const vector_array_type & r);
		void pdiff(real_type & u,vectorx_type & dp,const vectorx_type & p,const vector_array_type & r);
	};
	
	//!
	struct mors : potential
	{
		param_type p_E0,p_k,p_r0; //!
		mors(param_type p_E0,param_type p_k,param_type p_r0, array_index_type i,array_index_type j);
		static bool read(const std::string & input,const group_t & group,const topology_t& topology,potential_list_t & potential_list);
		std::string record_key() const;
		std::string record_params() const;
		void eval(real_type & u,vector_array_type & f,const vector_array_type & r) const;
	};
	struct mors_fit : mors, fit_base
	{
		vector_index_type i_E0,i_k,i_r0;
		mors_fit(param_type p_E0,  vector_index_type i_E0,
			param_type p_k,  vector_index_type i_k, 
			param_type p_r0, vector_index_type i_r0,  
			array_index_type i,array_index_type j);
		static bool read(const std::string & input,const group_t & group,const topology_t& topology,potential_fit_list_t & potential_list);
		void peval(real_type & u,vectorx_type & dp,const vectorx_type & p,const vector_array_type & r);
		void pdiff(real_type & u,vectorx_type & dp,const vectorx_type & p,const vector_array_type & r);
	};
	
}	


namespace angle
{
	struct potential : internal_potential
	{	
		array_index_type i,j,k; //! atom indecies
		potential(array_index_type i_,array_index_type j_,array_index_type k_);
		bool equivalent(const potential_base & r) const;
		std::string record_atom_index() const;
	};
	
	//!
	struct harm : potential
	{
		param_type p_k,p_phi0; //! k/2(phi_ijk-phi0)^2
		harm(param_type p_k,param_type p_phi0,
			 array_index_type i,array_index_type j,array_index_type k);
		static bool read(const std::string & input,const group_t & group,const topology_t& topology,potential_list_t & potential_list);
		std::string record_key() const;
		std::string record_params() const;
		void eval(real_type & u,vector_array_type & f,const vector_array_type & r) const;

	};
	struct harm_fit : harm, fit_base
	{
		vector_index_type i_k,i_phi0;
		harm_fit(param_type p_k,  vector_index_type i_k,
			 param_type p_phi0, vector_index_type i_phi0,
			 array_index_type i,array_index_type j,array_index_type k);
		static bool read(const std::string & input,const group_t & group,const topology_t& topology,potential_fit_list_t & potential_list);
		void peval(real_type & u,vectorx_type & dp,const vectorx_type & p,const vector_array_type & r);
		void pdiff(real_type & u,vectorx_type & dp,const vectorx_type & p,const vector_array_type & r);
	};
	
	//!
	struct hcos : potential
	{
		param_type p_k,p_cosphi0; //
		hcos(param_type p_k,param_type p_cosphi0,
			 array_index_type i,array_index_type j,array_index_type k);
		static bool read(const std::string & input,const group_t & group,const topology_t& topology,potential_list_t & potential_list);
		std::string record_key() const;
		std::string record_params() const;
		void eval(real_type & u,vector_array_type & f,const vector_array_type & r) const;

	};
	struct hcos_fit : hcos, fit_base
	{
		vector_index_type i_k,i_cosphi0;
		hcos_fit(param_type p_k,  vector_index_type i_k,
			 param_type p_cosphi0, vector_index_type i_cosphi0,
			 array_index_type i,array_index_type j,array_index_type k);
		static bool read(const std::string & input,const group_t & group,const topology_t& topology,potential_fit_list_t & potential_list);
		void peval(real_type & u,vectorx_type & dp,const vectorx_type & p,const vector_array_type & r);
		void pdiff(real_type & u,vectorx_type & dp,const vectorx_type & p,const vector_array_type & r);
	};
	

}	


namespace dihedral
{
	struct potential : internal_potential
	{	
		array_index_type i,j,k,l; //! atom indecies
		potential(array_index_type i_,array_index_type j_,array_index_type k_,array_index_type l_);
		bool equivalent(const potential_base & r) const;
		std::string record_atom_index() const;
	};
	
	//!
	struct harm : potential
	{
		param_type p_k,p_phi0; //! k/2(phi_ijk-phi0)^2
		harm(param_type p_k,param_type p_phi0,
			 array_index_type i,array_index_type j,array_index_type k,array_index_type l);
		static bool read(const std::string & input,const group_t & group,const topology_t& topology,potential_list_t & potential_list);
		std::string record_key() const;
		std::string record_params() const;
		void eval(real_type & u,vector_array_type & f,const vector_array_type & r) const;

	};
	struct harm_fit : harm, fit_base
	{
		vector_index_type i_k,i_phi0;
		harm_fit(param_type p_k,  vector_index_type i_k,
			 param_type p_phi0, vector_index_type i_phi0,
			 array_index_type i,array_index_type j,array_index_type k,array_index_type l);
		static bool read(const std::string & input,const group_t & group,const topology_t& topology,potential_fit_list_t & potential_list);
		void peval(real_type & u,vectorx_type & dp,const vectorx_type & p,const vector_array_type & r);
	};

	struct cosf : potential
	{
		param_type p_A,p_d,p_m; 
		cosf(param_type p_A,param_type p_d,param_type p_m,
			 array_index_type i,array_index_type j,array_index_type k,array_index_type l);
		static bool read(const std::string & input,const group_t & group,const topology_t& topology,potential_list_t & potential_list);
		std::string record_key() const;
		std::string record_params() const;
		void eval(real_type & u,vector_array_type & f,const vector_array_type & r) const;

	};
	struct cosf_fit : cosf
	{
		vector_index_type i_A,i_d,i_m; 
		cosf_fit(param_type p_A,  vector_index_type i_A,
			 param_type p_d, vector_index_type i_d,
			 param_type p_m, vector_index_type i_m,
			 array_index_type i,array_index_type j,array_index_type k,array_index_type l);
		static bool read(const std::string & input,const group_t & group,const topology_t& topology,potential_fit_list_t & potential_list);
		void peval(real_type & u,vectorx_type & dp,const vectorx_type & p,const vector_array_type & r);
	};

	//!
	/*
	struct hcos : potential
	{
		param_type p_k,p_cosphi0; //
		hcos(param_type p_k,param_type p_cosphi0,
			 array_index_type i,array_index_type j,array_index_type k,array_index_type l);
		static bool read(const std::string & input,structure_t & st);
		std::string record_key() const;
		std::string record_params() const;
		void eval(real_type & u,vector_array_type & f,const vector_array_type & r) const;

	};
	struct hcos_fit : hcos, fit_base
	{
		vector_index_type i_k,i_cosphi0;
		hcos_fit(param_type p_k,  vector_index_type i_k,
			 param_type p_cosphi0, vector_index_type i_cosphi0,
			 array_index_type i,array_index_type j,array_index_type k,array_index_type l);
		static bool read(const std::string & input,structure_t & st,real_array_type & params);
		void pdiff(real_type & u,vectorx_type & dp,const vectorx_type & p,const vector_array_type & r);
	};
	*/

}	









namespace inversion
{
	struct potential : internal_potential
	{	
		array_index_type i,j,k,l; //! atom indecies
		potential(array_index_type i_,array_index_type j_,array_index_type k_,array_index_type l_);
		bool equivalent(const potential_base & r) const;
		std::string record_atom_index() const;
	};
	
	//!
	struct plan : potential
	{
		param_type p_A;
		plan(param_type p_A,
			 array_index_type i,array_index_type j,array_index_type k,array_index_type l);
		static bool read(const std::string & input,const group_t & group,const topology_t& topology,potential_list_t & potential_list);
		std::string record_key() const;
		std::string record_params() const;
		void eval(real_type & u,vector_array_type & f,const vector_array_type & r) const;

	};
	struct plan_fit : plan
	{
		vector_index_type i_A;
		plan_fit(param_type p_A,  vector_index_type i_A,
			 array_index_type i,array_index_type j,array_index_type k,array_index_type l);
		static bool read(const std::string & input,const group_t & group,const topology_t& topology,potential_fit_list_t & potential_list);
		void peval(real_type & u,vectorx_type & dp,const vectorx_type & p,const vector_array_type & r);
	};
	
	//!

}	




struct external_potential : potential_base
{

};



#endif // POTENTIAL_H

